package com.fyb.basic.lock.pool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;

/** 自定义线程池类
 */
public class CustomThreadPool implements Executor {
    // 控制线程池状态的原子整数，默认为0（可能表示初始状态或其他特定含义，具体取决于后续逻辑）
    private final AtomicInteger ctl = new AtomicInteger(0);
    // 核心线程池大小，即在没有新任务提交时，线程池中保持的线程数量
    private volatile int corePoolSize;
    // 最大线程池大小，即线程池中允许的最大线程数量
    private volatile int maximumPoolSize;
    // 工作队列，用于存放待执行的任务
    private final BlockingQueue<Runnable> workQueue;
    // 构造函数，初始化线程池参数
    public CustomThreadPool(int corePoolSize, int maximumPoolSize,
                            BlockingQueue<Runnable> workQueue) {
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
    }
    @Override
    public void execute(Runnable command) {
        int c = ctl.get(); // 获取当前线程池的状态（由ctl表示）
        if (c < corePoolSize) {// 如果当前线程数小于核心线程池大小
            if (!addWorker(command)) { // 尝试添加一个新的工作线程并执行该任务
                reject(); // 如果添加工作线程失败（可能是因为达到某种限制或异常），则拒绝任务
            }
            return;// 任务已经提交给工作线程或被拒绝，返回
        }
        // 如果当前线程数已经达到核心线程池大小，尝试将任务放入工作队列
        if (!workQueue.offer(command)) {
            // 如果工作队列已满（即offer方法返回false），则尝试添加一个新的工作线程（即使这可能超过核心线程池大小）
            // 注意：这里应该有一个检查，确保不超过maximumPoolSize
            if (!addWorker(command)) {
                // 如果添加工作线程失败（可能是因为已经达到maximumPoolSize或其他原因），则拒绝任务
                reject();
            }
        }
    }
    // 添加工作线程并执行任务的辅助方法
    private boolean addWorker(Runnable firstTask) {
        // 如果当前线程数已经达到或超过最大线程池大小，则不再添加新的工作线程
        if (ctl.get() >= maximumPoolSize) {
            return false;
        }
        // 创建一个新的工作线程
        Worker worker = new Worker(firstTask);
        // 启动工作线程
        worker.thread.start();
        // 增加ctl的值，表示线程池中增加了一个工作线程
        ctl.incrementAndGet();
        /// 返回true表示成功添加了一个工作线程
        return true;
    }
    // 内部类Worker，表示一个工作线程
    private final class Worker implements Runnable {
        // 工作线程本身
        final Thread thread;
        // 该工作线程要执行的第一个任务（可能为null）
        Runnable firstTask;
        // 构造方法，创建一个新的工作线程
        public Worker(Runnable firstTask) {
            // 使用当前Worker实例作为Runnable来创建新的线程
            this.thread = new Thread(this);
            this.firstTask = firstTask;
        }
        // 实现Runnable接口的run方法，这是线程的主要执行逻辑
        @Override
        public void run() {
            // 获取第一个任务
            Runnable task = firstTask;
            try {
                // 当第一个任务不为null或者从工作队列中获取到任务时，执行任务
                while (task != null || (task = getTask()) != null) {
                    task.run();
                    task = null;
                }
            } finally {
                // 减少ctl的值，表示线程池中减少了一个工作线程
                ctl.decrementAndGet();
            }
        }
        // 从工作队列中获取任务的辅助方法
        private Runnable getTask() {
            for (; ; ) {
                try {
                    // 输出当前工作队列的大小（用于调试或日志记录）
                    System.out.println("workQueue.size：" + workQueue.size());
                    // 从工作队列中取出一个任务，如果队列为空，则此方法会阻塞等待
                    return workQueue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    // 拒绝策略直接抛出异常
    private void reject() {
        throw new RuntimeException("Error！ctl.count：" + ctl.get() + " workQueue.size：" + workQueue.size());
    }

    public static void main(String[] args) {
        //  第一个参数2：是核心线程数（corePoolSize），表示线程池中始终存在的线程数量。
        //  二个参数2：是最大线程数（maximumPoolSize），表示线程池中允许的最大线程数量。在这里，它和核心线程数相同，意味着线程池不会创建超过这个数量的线程。
        //  第三个参 数是一个ArrayBlockingQueue的实例，它用作线程池的工作队列，用于存放待执行的任务。这里的工作队列容量为10，表示最多可以存放10个待执行的任务。
        CustomThreadPool customThreadPool = new CustomThreadPool(2, 2,
                new ArrayBlockingQueue<Runnable>(10));
        // 用于提交10个任务到线程池。每个任务都是一个Lambda表达式
        for (int i = 0; i < 10; i++) {
            int finalI = i;
            customThreadPool.execute(() -> {
                try {
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务编号：" + finalI);
            });
        }
    }
}
